Imports System
Imports System.Collections.Generic
Imports System.Text


Public Class Tree_Node_List
    Inherits List(Of Tree_Node)

    Public Sub New()
    End Sub

    Public Sub New(ByVal nodes As Tree_Node_List, ByVal FirstIndex As Integer, ByVal LastIndex As Integer)
        Dim _StartIndex As Integer
        Dim _EndIndex As Integer
        If FirstIndex < LastIndex Then
            _StartIndex = Math.Max(0, FirstIndex)
            _EndIndex = Math.Min(nodes.Count - 1, LastIndex)
        Else
            _StartIndex = Math.Max(0, LastIndex)
            _EndIndex = Math.Min(nodes.Count - 1, FirstIndex)
        End If

        For i As Integer = FirstIndex To LastIndex
            Me.Add(nodes(i))
        Next
    End Sub

    Public Sub New(ByVal nodes As Tree_Node_List, ByVal FirstItem As Tree_Node, ByVal LastItem As Tree_Node)
        Me.New(nodes, nodes.IndexOf(FirstItem), nodes.IndexOf(LastItem))
    End Sub
End Class



Public Class Tree_Node
    Protected _ReturnType As ReturnType = ReturnType.none
    Protected _ParentNode As Tree_Node = Nothing
    Protected _ChildNodes As Tree_Node_List
    Protected _Represents As Token

    Public Sub New(ByVal t As Token)
        _Represents = t
    End Sub

    Public Shared Function BuildTree(ByVal Owner As Parser, ByVal t As Tokenizer) As Tree_Node_List
        Return BuildTree(Owner, t, 0, t.Count - 1)
    End Function

    Protected Shared Function BuildTree(ByVal Owner As Parser, ByVal t As Tokenizer, ByVal FirstIndex As Integer, ByVal LastIndex As Integer) As Tree_Node_List
        Dim TmpResult As New Tree_Node_List()

        ' Convert Tokens to Nodes and break down grouping (parentesis)
        For i As Integer = FirstIndex To LastIndex
            If Tree_Node_Number.Match(t(i)) Then
                TmpResult.Add(New Tree_Node_Number(t(i)))
            ElseIf Tree_Node_String.Match(t(i)) Then
                TmpResult.Add(New Tree_Node_String(t(i)))
            ElseIf Tree_Node_Separator.Match(t(i)) Then
                TmpResult.Add(New Tree_Node_Separator(t(i)))
            ElseIf Tree_Node_Parentesis.MatchOpening(t(i)) Then
                Dim BracesCounter As Integer = 1
                For j As Integer = i + 1 To LastIndex
                    If Tree_Node_Parentesis.MatchOpening(t(j)) Then
                        BracesCounter += 1
                    ElseIf Tree_Node_Parentesis.MatchClosing(t(j)) Then
                        BracesCounter -= 1
                        If BracesCounter = 0 Then
                            TmpResult.Add(New Tree_Node_Parentesis(Owner, t, i, j))
                            i = j
                            Exit For
                        End If
                    End If
                Next
                If BracesCounter <> 0 Then
                    TmpResult.Add(New Tree_Node(t(i)))
                End If
            ElseIf Tree_Node_Designator.Match(Owner, t(i)) Then
                t(i).Tag = Owner.Designators(t(i).ToString().ToLower())
                TmpResult.Add(New Tree_Node_Designator(t(i)))
            Else
                TmpResult.Add(New Tree_Node(t(i)))
            End If
        Next

        ' Scan nodes for Expressions (between Separators)
        Dim CurrentIndex As Integer = TmpResult.Count - 1
        For i As Integer = TmpResult.Count - 1 To 0 Step -1
            If TypeOf TmpResult(i) Is Tree_Node_Separator Then
                ParseExpression(Owner, TmpResult, i + 1, CurrentIndex)
                CurrentIndex = i - 1
            End If
        Next
        ParseExpression(Owner, TmpResult, 0, CurrentIndex)

        Return TmpResult
    End Function


    Protected Shared Sub ParseExpression(ByVal Owner As Parser, ByRef nodes As Tree_Node_List, ByVal FirstIndex As Integer, ByVal LastIndex As Integer)


        ' Scan for AND/OR Operators
        If Tree_Node_OpAndOr.Scan(Owner, nodes, FirstIndex, LastIndex) Then Exit Sub

        ' Scan for Compare-Operators (>, <, =, >=, <=, <>)
        If Tree_Node_OpCompare.Scan(Owner, nodes, FirstIndex, LastIndex) Then Exit Sub

        ' Scan for general Operators (||, +, -, *, /, ^)
        If Tree_Node_OpGeneral.Scan(Owner, nodes, FirstIndex, LastIndex) Then Exit Sub

        ' Scan for NOT Operators
        If Tree_Node_OpNot.Scan(Owner, nodes, FirstIndex, LastIndex) Then Exit Sub

        ' Scan for IN Operators
        If Tree_Node_OpIn.Scan(Owner, nodes, FirstIndex, LastIndex) Then Exit Sub

        ' Scan nodes for Functions
        If Not Owner.Functions Is Nothing AndAlso Tree_Node_Function.Scan(Owner, nodes, FirstIndex, LastIndex) Then Exit Sub

    End Sub

    Public ReadOnly Property ChildNodes() As Tree_Node_List
        Get
            Return _ChildNodes
        End Get
    End Property

    Public ReadOnly Property HasChildren() As Boolean
        Get
            Return _ChildNodes IsNot Nothing AndAlso _ChildNodes.Count > 0
        End Get
    End Property

    Public Property ParentNode() As Tree_Node
        Get
            Return _ParentNode
        End Get
        Set(ByVal value As Tree_Node)
            _ParentNode = value
        End Set
    End Property

    Public ReadOnly Property ReturnType() As ReturnType
        Get
            Return _ReturnType
        End Get
    End Property

    Public Overridable ReadOnly Property Length() As Integer
        Get
            Return _Represents.Length
        End Get
    End Property

    Public ReadOnly Property Offset() As Integer
        Get
            Return _Represents.Offset
        End Get
    End Property

    Public ReadOnly Property Token() As Token
        Get
            Return _Represents
        End Get
    End Property


    Public Overloads Overrides Function ToString() As String
        Return _Represents.ToString()
    End Function
End Class



Public Class Tree_Node_Number
    Inherits Tree_Node
    Public Shared Function Match(ByVal t As Token) As Boolean
        Return TypeOf t Is Token_NumberLiteral
    End Function

    Public Sub New(ByVal t As Token)
        MyBase.New(t)
        _ReturnType = ReturnType.Number
        t.Type = Token_Type.NumberLiteral
    End Sub
End Class


Public Class Tree_Node_String
    Inherits Tree_Node
    Public Shared Function Match(ByVal t As Token) As Boolean
        Return TypeOf t Is Token_StringLiteral
    End Function

    Public Sub New(ByVal t As Token)
        MyBase.New(t)
        _ReturnType = ReturnType.[String]
        t.Type = Token_Type.StringLiteral
    End Sub
End Class


Public Class Tree_Node_OpCompare
    Inherits Tree_Node
    Public Shared Function Match(ByVal t As Token) As Boolean
        Dim TokenStr As String = t.ToString()

        Return (t.Previous IsNot Nothing AndAlso t.[Next] IsNot Nothing) AndAlso (TokenStr.Equals("<>") OrElse TokenStr.Equals("<=") OrElse TokenStr.Equals(">=") OrElse TokenStr.Equals("<") OrElse TokenStr.Equals("=") OrElse TokenStr.Equals(">") OrElse (TokenStr.Equals("LIKE", StringComparison.OrdinalIgnoreCase) AndAlso TypeOf t.[Next] Is Token_StringLiteral))
    End Function

    Public Shared Function Scan(ByVal Owner As Parser, ByRef nodes As Tree_Node_List, ByVal FirstIndex As Integer, ByVal LastIndex As Integer) As Boolean
        For i As Integer = LastIndex To FirstIndex Step -1
            If Tree_Node_OpCompare.Match(nodes(i).Token) Then
                Dim TmpNode As Tree_Node = nodes(i)
                Tree_Node.ParseExpression(Owner, nodes, i + 1, LastIndex)
                Tree_Node.ParseExpression(Owner, nodes, FirstIndex, i - 1)
                Dim NodeIndex As Integer = nodes.IndexOf(TmpNode)
                If NodeIndex > 0 AndAlso NodeIndex < nodes.Count - 1 Then
                    nodes(NodeIndex) = New Tree_Node_OpCompare(TmpNode.Token, nodes(NodeIndex - 1), nodes(NodeIndex + 1))
                    nodes.RemoveAt(NodeIndex + 1)
                    nodes.RemoveAt(NodeIndex - 1)
                End If
                Return True
            End If
        Next
        Return False
    End Function

    Public Sub New(ByVal t As Token, ByVal LeftNode As Tree_Node, ByVal RightNode As Tree_Node)
        MyBase.New(t)
        _ChildNodes = New Tree_Node_List()
        _ChildNodes.Add(LeftNode)
        _ChildNodes.Add(RightNode)
        _ReturnType = ReturnType.[Boolean]
        t.Type = Token_Type.Oparator
    End Sub
End Class



Public Class Tree_Node_OpGeneral
    Inherits Tree_Node
    Public Shared Function Match(ByVal t As Token) As Boolean
        Dim TokenStr As String = t.ToString()
        Return (t.Previous IsNot Nothing AndAlso t.[Next] IsNot Nothing) AndAlso (TokenStr.Equals("||") OrElse TokenStr.Equals("+") OrElse TokenStr.Equals("-") OrElse TokenStr.Equals("*") OrElse TokenStr.Equals("/") OrElse TokenStr.Equals("^"))
    End Function

    Public Shared Function Scan(ByVal Owner As Parser, ByRef nodes As Tree_Node_List, ByVal FirstIndex As Integer, ByVal LastIndex As Integer) As Boolean
        For i As Integer = LastIndex To FirstIndex Step -1
            If Tree_Node_OpGeneral.Match(nodes(i).Token) Then
                Dim TmpNode As Tree_Node = nodes(i)
                Tree_Node.ParseExpression(Owner, nodes, i + 1, LastIndex)
                Tree_Node.ParseExpression(Owner, nodes, FirstIndex, i - 1)
                Dim NodeIndex As Integer = nodes.IndexOf(TmpNode)
                If NodeIndex > 0 AndAlso NodeIndex < nodes.Count - 1 Then
                    nodes(NodeIndex) = New Tree_Node_OpGeneral(TmpNode.Token, nodes(NodeIndex - 1), nodes(NodeIndex + 1))
                    nodes.RemoveAt(NodeIndex + 1)
                    nodes.RemoveAt(NodeIndex - 1)
                End If
                Return True
            End If
        Next
        Return False
    End Function

    Public Sub New(ByVal t As Token, ByVal LeftNode As Tree_Node, ByVal RightNode As Tree_Node)
        MyBase.New(t)
        _ChildNodes = New Tree_Node_List()
        _ChildNodes.Add(LeftNode)
        _ChildNodes.Add(RightNode)
        If t.ToString().Equals("||") Then
            _ReturnType = ReturnType.[String]
        Else
            _ReturnType = ReturnType.Number
        End If
        t.Type = Token_Type.Oparator
    End Sub
End Class

Public Class Tree_Node_OpAndOr
    Inherits Tree_Node
    Public Shared Function Match(ByVal t As Token) As Boolean
        Dim TokenStr As String = t.ToString()
        Return (t.Previous IsNot Nothing AndAlso t.[Next] IsNot Nothing) AndAlso (t.WhiteSpacesFollowing > 0) AndAlso (TokenStr.Equals("AND", StringComparison.OrdinalIgnoreCase) OrElse TokenStr.Equals("OR", StringComparison.OrdinalIgnoreCase))
    End Function

    Public Shared Function Scan(ByVal Owner As Parser, ByRef nodes As Tree_Node_List, ByVal FirstIndex As Integer, ByVal LastIndex As Integer) As Boolean
        For i As Integer = LastIndex To FirstIndex Step -1
            If Tree_Node_OpAndOr.Match(nodes(i).Token) Then
                Dim TmpNode As Tree_Node = nodes(i)
                Tree_Node.ParseExpression(Owner, nodes, i + 1, LastIndex)
                Tree_Node.ParseExpression(Owner, nodes, FirstIndex, i - 1)
                Dim NodeIndex As Integer = nodes.IndexOf(TmpNode)
                If NodeIndex > 0 AndAlso NodeIndex < nodes.Count - 1 Then
                    nodes(NodeIndex) = New Tree_Node_OpAndOr(TmpNode.Token, nodes(NodeIndex - 1), nodes(NodeIndex + 1))
                    nodes.RemoveAt(NodeIndex + 1)
                    nodes.RemoveAt(NodeIndex - 1)
                End If
                Return True
            End If
        Next
        Return False
    End Function

    Public Sub New(ByVal t As Token, ByVal LeftNode As Tree_Node, ByVal RightNode As Tree_Node)
        MyBase.New(t)
        _ChildNodes = New Tree_Node_List()
        _ChildNodes.Add(LeftNode)
        _ChildNodes.Add(RightNode)
        _ReturnType = ReturnType.[Boolean]
        t.Type = Token_Type.Oparator
    End Sub
End Class


Public Class Tree_Node_OpNot
    Inherits Tree_Node
    Public Shared Function Match(ByVal t As Token) As Boolean
        Dim TokenStr As String = t.ToString()
        Return (TokenStr.Equals("NOT", StringComparison.OrdinalIgnoreCase) AndAlso (t.WhiteSpacesFollowing > 0) AndAlso t.[Next] IsNot Nothing)
    End Function

    Public Shared Function Scan(ByVal Owner As Parser, ByRef nodes As Tree_Node_List, ByVal FirstIndex As Integer, ByVal LastIndex As Integer) As Boolean
        For i As Integer = LastIndex To FirstIndex Step -1
            If Tree_Node_OpNot.Match(nodes(i).Token) Then
                Dim TmpNode As Tree_Node = nodes(i)
                Tree_Node.ParseExpression(Owner, nodes, i + 1, LastIndex)
                Dim NodeIndex As Integer = nodes.IndexOf(TmpNode)
                If NodeIndex >= 0 AndAlso NodeIndex < nodes.Count - 1 Then
                    nodes(NodeIndex) = New Tree_Node_OpNot(TmpNode.Token, nodes(NodeIndex + 1))
                    nodes.RemoveAt(NodeIndex + 1)
                End If
                Return True
            End If
        Next
        Return False
    End Function

    Public Sub New(ByVal t As Token, ByVal RightNode As Tree_Node)
        MyBase.New(t)
        _ChildNodes = New Tree_Node_List()
        _ChildNodes.Add(RightNode)
        _ReturnType = ReturnType.[Boolean]
        t.Type = Token_Type.Oparator
    End Sub
End Class


Public Class Tree_Node_OpBetwween
    Inherits Tree_Node
    Public Shared Function Match(ByVal t As Token) As Boolean
        Dim TokenStr As String = t.ToString()
        Return TokenStr.Equals("BETWEEN", StringComparison.OrdinalIgnoreCase)
    End Function

    Public Shared Function Scan(ByVal Owner As Parser, ByRef nodes As Tree_Node_List, ByVal FirstIndex As Integer, ByVal LastIndex As Integer) As Boolean

        Return False
    End Function

    Public Sub New(ByVal t As Token)
        MyBase.New(t)
        t.Type = Token_Type.Oparator
    End Sub
End Class


Public Class Tree_Node_OpIn
    Inherits Tree_Node
    Public Shared Function Match(ByVal t As Token) As Boolean
        Dim TokenStr As String = t.ToString()
        Return t.Previous IsNot Nothing AndAlso TypeOf t.[Next] Is Token_Parentesis AndAlso TokenStr.Equals("IN", StringComparison.OrdinalIgnoreCase)
    End Function

    Public Shared Function Scan(ByVal Owner As Parser, ByRef nodes As Tree_Node_List, ByVal FirstIndex As Integer, ByVal LastIndex As Integer) As Boolean
        For i As Integer = LastIndex To FirstIndex Step -1
            If Tree_Node_OpIn.Match(nodes(i).Token) Then
                Dim TmpNode As Tree_Node = nodes(i)
                Tree_Node.ParseExpression(Owner, nodes, i + 1, LastIndex)
                Tree_Node.ParseExpression(Owner, nodes, FirstIndex, i - 1)
                Dim NodeIndex As Integer = nodes.IndexOf(TmpNode)
                If NodeIndex > 0 AndAlso NodeIndex < nodes.Count - 1 Then
                    nodes(NodeIndex) = New Tree_Node_OpIn(TmpNode.Token, nodes(NodeIndex - 1), nodes(NodeIndex + 1))
                    nodes.RemoveAt(NodeIndex + 1)
                    nodes.RemoveAt(NodeIndex - 1)
                End If
                Return True
            End If
        Next
        Return False
    End Function

    Public Sub New(ByVal t As Token, ByVal LeftNode As Tree_Node, ByVal RightNode As Tree_Node)
        MyBase.New(t)
        t.Type = Token_Type.Oparator
        _ChildNodes = New Tree_Node_List()
        _ChildNodes.Add(LeftNode)
        _ChildNodes.Add(RightNode)
        _ReturnType = ReturnType.[Boolean]
        t.Type = Token_Type.Oparator
    End Sub
End Class


Public Class Tree_Node_Designator
    Inherits Tree_Node

    Public Shared Function Match(ByVal t As Token) As Boolean
        Dim TokenStr As String = t.ToString()
        Return TokenStr.StartsWith("_") OrElse Char.IsLetter(TokenStr(0))
    End Function

    Public Shared Function Match(ByVal Owner As Parser, ByVal t As Token) As Boolean
        Return (Match(t) AndAlso Owner.Designators.ContainsKey(t.ToString().ToLower()))
    End Function

    Public Sub New(ByVal t As Token)
        MyBase.New(t)
        t.Type = Token_Type.KnownDesignator
    End Sub
End Class

Public Class Tree_Node_Separator
    Inherits Tree_Node
    Public Shared Function Match(ByVal t As Token) As Boolean
        Dim TokenStr As String = t.ToString()
        Return (t.Previous IsNot Nothing AndAlso t.[Next] IsNot Nothing) AndAlso TokenStr.Equals(",")
    End Function

    Public Sub New(ByVal t As Token)
        MyBase.New(t)
        t.Type = Token_Type.Separator
    End Sub
End Class


Public Class Tree_Node_Parentesis
    Inherits Tree_Node
    Protected _RepresentsEnd As Token

    Public Shared Function MatchOpening(ByVal t As Token) As Boolean
        Return t.ToString().Equals("(")
    End Function

    Public Shared Function MatchClosing(ByVal t As Token) As Boolean
        Return t.ToString().Equals(")")
    End Function

    Public Sub New(ByVal Owner As Parser, ByVal t As Tokenizer, ByVal FirstIndex As Integer, ByVal LastIndex As Integer)
        MyBase.New(t(FirstIndex))
        _RepresentsEnd = t(LastIndex)
        _ChildNodes = Tree_Node.BuildTree(Owner, t, FirstIndex + 1, LastIndex - 1)
        For Each item As Tree_Node In _ChildNodes
            item.ParentNode = Me
        Next

        _Represents.Type = Token_Type.Parentesis
        _RepresentsEnd.Type = Token_Type.Parentesis
    End Sub

    Public Overloads Overrides Function ToString() As String
        Return _Represents.ToString() + New String(" "c, _RepresentsEnd.Offset - _Represents.Offset - 1) + _RepresentsEnd.ToString()
    End Function

    Public Overrides ReadOnly Property Length() As Integer
        Get
            Return _RepresentsEnd.Offset - _Represents.Offset + _RepresentsEnd.Length
        End Get
    End Property
End Class






Public Class Tree_Node_Function
    Inherits Tree_Node

    Public Sub New(ByVal Owner As Parser, ByVal FuncDef As ParserFuncDef, ByVal t As Token, ByVal nodes As Tree_Node_List)
        MyBase.New(t)
        _ChildNodes = nodes

        'mark underlying tokens as part of the function
        Dim FirstTokenIndex As Integer = Owner.Tokens.TokenIndexByStringPos(nodes(0).Offset)
        Dim LastTokenIndex As Integer = Owner.Tokens.TokenIndexByStringPos(nodes(nodes.Count - 1).Offset + nodes(nodes.Count - 1).Length - 1)
        For j As Integer = FirstTokenIndex To LastTokenIndex
            If Owner.Tokens(j).Type = Token_Type.Unknown AndAlso _
              Tree_Node_Designator.Match(Owner.Tokens(j)) AndAlso _
              FuncDef.ToString.IndexOf(Owner.Tokens(j).ToString.ToUpper) >= 0 Then
                Owner.Tokens(j).Type = Token_Type.FunctionDesignator
            End If

            _ReturnType = FuncDef.[Return].Type

        Next
    End Sub


    ''' <summary>
    ''' 
    ''' </summary>
    ''' <param name="Item"></param>
    ''' <param name="nodes"></param>
    ''' <param name="FirstIndex"></param>
    ''' <param name="LastIndex"></param>
    ''' <returns>Number of nodes (length) or -1 if no match.</returns>
    Private Shared Function CheckFuncDefItem(ByVal Item As ParserFuncDef_Item, ByVal nodes As Tree_Node_List, ByVal FirstIndex As Integer, ByVal LastIndex As Integer) As Integer

        Dim ItemType As ParserFuncDef_ItemType = Item.ItemType

        If FirstIndex >= nodes.Count OrElse LastIndex >= nodes.Count Then
            If ItemType = ParserFuncDef_ItemType.OptionalGroup Then
                Return 0
            Else
                Return -1
            End If

        End If



        If ItemType = ParserFuncDef_ItemType.Designator Then
            If Item.ToString().Equals(nodes(FirstIndex).Token.ToString(), StringComparison.OrdinalIgnoreCase) Then
                Return 1
                'nodes(FirstIndex).Token.Tag=item
            Else
                Return -1
            End If

        ElseIf ItemType = ParserFuncDef_ItemType.Parentesis AndAlso TypeOf nodes(FirstIndex) Is Tree_Node_Parentesis Then
            If Not Item.HasChildren AndAlso Not nodes(FirstIndex).HasChildren OrElse _
               CheckFuncDefPattern(Item.Children, nodes(FirstIndex).ChildNodes, 0, nodes(FirstIndex).ChildNodes.Count - 1) = nodes(FirstIndex).ChildNodes.Count Then
                Return 1
            Else
                Return -1
            End If
        ElseIf ItemType = ParserFuncDef_ItemType.Separator AndAlso TypeOf nodes(FirstIndex) Is Tree_Node_Separator Then
            Return 1
        ElseIf ItemType = ParserFuncDef_ItemType.Expression AndAlso Not TypeOf nodes(FirstIndex) Is Tree_Node_Separator Then
            Return 1
        ElseIf ItemType = ParserFuncDef_ItemType.OptionalGroup Then
            Dim Ofs As Integer
            Dim OptGroupItem As ParserFuncDef_OptionalGroup = DirectCast(Item, ParserFuncDef_OptionalGroup)

            If OptGroupItem.RepeatType = ParserFuncDef_OptionalRepeatType.[Optional] Then
                Ofs = CheckFuncDefPattern(OptGroupItem.Children, nodes, FirstIndex, LastIndex)
                If Ofs > 0 Then
                    Return Ofs
                Else
                    Return 0
                End If
            ElseIf OptGroupItem.RepeatType = ParserFuncDef_OptionalRepeatType.RepeatOptional Then
                Dim OfsSum As Integer = 0
                Do
                    Ofs = CheckFuncDefPattern(OptGroupItem.Children, nodes, FirstIndex + OfsSum, LastIndex)
                    If Ofs > 0 Then
                        OfsSum += Ofs
                    End If
                Loop While Ofs > 0
                Return OfsSum
            ElseIf OptGroupItem.RepeatType = ParserFuncDef_OptionalRepeatType.Group Then
                Ofs = CheckFuncDefPattern(OptGroupItem.Children, nodes, FirstIndex, LastIndex)
                If Ofs > 0 Then
                    Return Ofs
                Else
                    Return -1
                End If
            ElseIf OptGroupItem.RepeatType = ParserFuncDef_OptionalRepeatType.Repeat Then
                Dim OfsSum As Integer = 0
                Do
                    Ofs = CheckFuncDefPattern(OptGroupItem.Children, nodes, FirstIndex + OfsSum, LastIndex)
                    If Ofs > 0 Then
                        OfsSum += Ofs
                    End If
                Loop While Ofs > 0
                If OfsSum > 0 Then
                    Return OfsSum
                Else
                    Return -1
                End If

            End If

            Return 0
        ElseIf ItemType = ParserFuncDef_ItemType.Alternative Then
            Dim Ofs As Integer
            For Each alternative As ParserFuncDef_Item In Item.Children
                Ofs = CheckFuncDefItem(alternative, nodes, FirstIndex, LastIndex)
                If Ofs > 0 Then
                    Return Ofs
                End If
            Next
            Return -1
        End If

        Return -1
    End Function

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <param name="DefItems"></param>
    ''' <param name="nodes"></param>
    ''' <param name="FirstIndex"></param>
    ''' <param name="LastIndex"></param>
    ''' <returns>Offset from "FirstIndex" to the next node or -1 if no match.</returns>
    Private Shared Function CheckFuncDefPattern(ByVal DefItems As ParserFuncDef_ItemList, ByVal nodes As Tree_Node_List, ByVal FirstIndex As Integer, ByVal LastIndex As Integer) As Integer
        Dim CurIndex As Integer = FirstIndex
        Dim Ofs As Integer
        For Each item As ParserFuncDef_Item In DefItems
            Ofs = CheckFuncDefItem(item, nodes, CurIndex, LastIndex)
            If Ofs > 0 Then
                CurIndex += Ofs
            ElseIf Ofs = 0 Then
                Continue For
            Else
                Return -1
            End If
        Next

        Return CurIndex - FirstIndex
    End Function

    Public Shared Function Scan(ByVal Owner As Parser, ByRef nodes As Tree_Node_List, ByVal FirstIndex As Integer, ByVal LastIndex As Integer) As Boolean
        Dim Ofs As Integer
        For i As Integer = FirstIndex To LastIndex - 1
            If (Tree_Node_Designator.Match(nodes(i).Token)) AndAlso (nodes(i).Token.WhiteSpacesFollowing = 0) Then
                For Each item As KeyValuePair(Of String, ParserFuncDef) In Owner.Functions

                    'If nodes(i).Token.ToString.Equals(item.Value.Items(0).ToString, StringComparison.OrdinalIgnoreCase) Then
                    '    nodes(i).Token.Tag = item.Value
                    'End If

                    Ofs = CheckFuncDefPattern(item.Value.Items, nodes, i, LastIndex)
                    If Ofs > 0 Then
                        Dim TmpNodes As New Tree_Node_List(nodes, i, i + Ofs - 1)
                        TmpNodes(0).Token.Tag = item.Value
                        nodes.RemoveRange(i, Ofs)
                        nodes.Insert(i, New Tree_Node_Function(Owner, item.Value, TmpNodes(0).Token, TmpNodes))
                        Return True
                    End If
                Next
            End If
        Next

        Return False
    End Function

    Public Overloads Overrides Function ToString() As String
        Return _Represents.ToString()
    End Function
End Class

